﻿using System;
using System.Collections.Generic;
using System.Text;
using Estimate.Common.DBFieldTypes;
using Estimate.Common.Repository;
using Estimate.Common.Entity;

namespace Estimate.Common.Estimate
{
    /// <summary>
    /// 获取某个预报名的semi字符串
    /// </summary>
    public class IndividualSemi
    {
        private ForeRepository _foreRepository;

        private ScheduleRepository _scheduleRepository;

        private AffiliationRepository _affiliationRepository;

        public IndividualSemi(string connectionString)
        {              
            _scheduleRepository = new ScheduleRepository(connectionString);
            _affiliationRepository = new AffiliationRepository(connectionString);
        }

        public ForeEntity[] InquerySemiWithDateRange(ForeRepository repository, string forecaster, DateTime beginDate, DateTime endDate, ForeClockType[] clocks, ForeSpanType span, ForeSendpointType[] sendpoints, ForeFactorType type, ForeSemiType semitype)
        {

            //查找符合条件的 Schedule对象
            string station = forecaster.Split(new char[] { '_' })[0];

            ScheduleType scheduleType = GetScheduleType(station);
            _foreRepository = repository;

            List<ScheduleEntity> scheduleEntites = new List<ScheduleEntity>();

            scheduleEntites.AddRange(_scheduleRepository.GetSchedulesWithDateRange(scheduleType, beginDate, endDate, clocks, span, sendpoints, station));
            scheduleEntites = FilterSchedule(scheduleEntites, forecaster);


            //查找符合条件的 Fore 对象
            List<ForeEntity> foreEntites = new List<ForeEntity>();
            ForeEntity[] entites = _foreRepository.GetForeRecordWithDateRange(beginDate, endDate, clocks, new ForeSpanType[] { span }, sendpoints, new ForeFactorType[] { type }, semitype, true);
            foreEntites.AddRange(entites);
            foreEntites = FilterSemi(station, scheduleType, foreEntites);


            return FilterSemiWithScedule(foreEntites, scheduleEntites);
        }

        private ScheduleType GetScheduleType(string station)
        {
            //如果是00001站点，表示是指导站点，否则说明是城镇报
            if (station == "00001")
            {
                return ScheduleType.zd;
            }
            else
            {
                return ScheduleType.cz;
            }
        }

        private List<ScheduleEntity> FilterSchedule(List<ScheduleEntity> scheduleEntites, string forecaster)
        {
            //根据schedule对象，重新确定实况的时间范围
            //同时，检查预报员中是否有需要的预报员，只保留需要的预报员
            List<ScheduleEntity> leftScheduleEntites = new List<ScheduleEntity>(scheduleEntites.Count);
            foreach (ScheduleEntity schedule in scheduleEntites)
            {
                if (schedule.ForecastNumber.IndexOf(forecaster) != -1)
                {
                    leftScheduleEntites.Add(schedule);
                }
            }
            return leftScheduleEntites;
        }


        private List<ForeEntity> FilterSemi(string station, ScheduleType scheduleType, List<ForeEntity> foreEntites)
        {
            string destStations = _affiliationRepository.GetAreaSubStationsString(station);

            //进行数据匹配，找出预报员播报的semi

            //先对value进行筛选，保留与站点有关系的semi

            if (scheduleType != ScheduleType.zd)
            {
                List<ForeEntity>  leftForeEntites = new List<ForeEntity>(foreEntites.Count);
                foreach (ForeEntity entity in foreEntites)
                {
                    if (destStations.Length > 0)
                    {
                        string semi = _foreRepository.FilterSemiWithStationIds(entity.Semi, destStations);
                        if (semi.Length > 5)
                        {
                            entity.Semi = semi;
                            leftForeEntites.Add(entity);
                        }
                    }
                    else
                    {
                        leftForeEntites.Add(entity);
                    }
                }
                return leftForeEntites;
            }
            return foreEntites;
        }


        /// <summary>
        /// 在获得属于个人的排班表，及相应的预报后，进行筛选，得出用户的semi
        /// </summary>
        /// <param name="foreEntites">预报数组</param>
        /// <param name="scheduleEntites">排班表数组</param>
        /// <returns>属于用户的预报数组</returns>
        private ForeEntity[] FilterSemiWithScedule(List<ForeEntity> foreEntites, List<ScheduleEntity> scheduleEntites)
        {
            List<ForeEntity> result = new List<ForeEntity>(foreEntites.Count);
            Comparison<ForeEntity> comForeEntity = new Comparison<ForeEntity>(compareForeEntity);
            Comparison<ScheduleEntity> comScheduleEntity = new Comparison<ScheduleEntity>(compareScheduleEntit);
            foreEntites.Sort(comForeEntity);
            scheduleEntites.Sort(comScheduleEntity);
            int curForeEntity = 0;
            int curScheduleEntity = 0;
            int fMax = 0;
            int fMin = 0;
            int sMax = 0;
            int sMin = 0;
            //说明：在将 fore, schedule分别按日期排好序的情况下。只需要将同一天的数据进行循环比较
            //      就可以确定哪些预报是属于预报员的
            if (foreEntites.Count > 0 && scheduleEntites.Count > 0)
            {
                while (curForeEntity < foreEntites.Count && curScheduleEntity < scheduleEntites.Count)
                {
                    DateTime curDate = scheduleEntites[curScheduleEntity].RealDate;

                    for (int i = curForeEntity; i < foreEntites.Count; i++)
                    {
                        if (curDate == foreEntites[i].Date)
                        {
                            curForeEntity = i;
                            break;
                        }
                        if (foreEntites[i].Date > curDate)
                            break;
                    }

                    
                    ScheduleEntity schedule = scheduleEntites[curScheduleEntity];
                    bool cs = false; 
                    for (int i = curForeEntity; foreEntites[i].Date == curDate; i++)
                    {
                        ForeEntity fore = foreEntites[i];
                        if (fore.Clock == schedule.Clock && fore.Sendpoint == schedule.Sendpoint
                                && fore.Span == schedule.Span
                                && (fore.Date.Year == schedule.RealDate.Year && fore.Date.DayOfYear == schedule.RealDate.DayOfYear))
                        {

                            result.Add(fore);
                            cs = true;
                            break;
                        }
                    }

                    curScheduleEntity += 1;

                }
            }
            
            return result.ToArray();
        }

        private int compareForeEntity(ForeEntity entity1, ForeEntity entity2)
        {
            return entity1.Date.CompareTo(entity2.Date);
        }

        private int compareScheduleEntit(ScheduleEntity entity1, ScheduleEntity entity2)
        {
            return entity1.RealDate.CompareTo(entity2.RealDate);
        }
    }
}
